package com.hoapital.outpbillwork.billWorkHandler;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hoapital.outpbillwork.module.controller.vo.ApplyInfo;
import com.hoapital.outpbillwork.module.controller.vo.ItemData;
import com.hoapital.outpbillwork.module.controller.vo.OrderInfo;
import com.hoapital.outpbillwork.module.entity.*;
import com.hoapital.outpbillwork.module.mapper.*;
import com.hoapital.outpbillwork.module.service.OutpDoctorAssistantService;
import com.hospital.api.RemoteBillService;
import com.hospital.common.core.constants.AllFinalValueUtils;
import com.hospital.common.core.constants.OrderConstant;
import com.hospital.common.core.exception.ExceptionHelp;
import com.hospital.common.core.exception.ExceptionHelpEnum;
import com.hospital.common.core.hl7Model.hospitalWork.BATCH;
import com.hoapital.outpbillwork.function.setValue.SetFunctionHL7;

import com.hospital.common.core.module.controller.vo.CancelOrder;
import com.hospital.common.core.module.controller.vo.OrderContent;
import com.hospital.common.core.module.controller.vo.Receive;
import com.hospital.common.core.result.SuccessTip;
import com.hospital.common.core.result.Tip;
import com.hospital.common.core.utils.DateUtil;
import com.hospital.common.core.utils.SpringContextHolder;
import com.hospital.common.core.utils.XMLUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author lvyao
 * @description 门诊开单处方
 * @date 2022/2/25
 */

@Transactional(rollbackFor = Exception.class)
public class PrescOrderBusiness extends AbstractOrderWorkBusiness {

    private OutpDoctorPrescMasterMapper outpDoctorPrescMasterMapper = SpringContextHolder.getBean(OutpDoctorPrescMasterMapper.class);

    private OutpDoctorPrescItemsMapper outpDoctorPrescItemsMapper = SpringContextHolder.getBean(OutpDoctorPrescItemsMapper.class);

    private LabTestMasterMapper labTestMasterMapper = SpringContextHolder.getBean(LabTestMasterMapper.class);

    private OutpOrderDescTempMapper outpOrderDescTempMapper = SpringContextHolder.getBean(OutpOrderDescTempMapper.class);

    private OutpOrderDescMapper outpOrderDescMapper = SpringContextHolder.getBean(OutpOrderDescMapper.class);

    private OutpDoctorAssistantService outpDoctorAssistantService = SpringContextHolder.getBean(OutpDoctorAssistantService.class);


    private ThreadPoolExecutor threadPoolExecutor = SpringContextHolder.getBean(ThreadPoolExecutor.class);

    @Override
    public ExceptionHelp checkOtherOrder(OrderInfo orderInfo) throws ExceptionHelp {
        return null;
    }

    @Override
    public ExceptionHelp checkOtherExpecOrder(ApplyInfo orderInfo) throws ExceptionHelp {
        String specimen = orderInfo.getOrder().getChronicFlag();
        if (StringUtils.isBlank(specimen)) {
            return new ExceptionHelp(ExceptionHelpEnum.NULL_CHRONIC);
        }
        List<ItemData> itemDataList = orderInfo.getItemData();
        for (ItemData itemData : itemDataList) {
            if (StringUtils.isBlank(itemData.getFrequency()) || StringUtils.isBlank(itemData.getDosage()) || StringUtils.isBlank(itemData.getAdministration()) ||
                    ObjectUtil.isNull(itemData.getDays()) || itemData.getDays() == 0) {
                return new ExceptionHelp(ExceptionHelpEnum.NULL_PRESC_FILEDS);
            }
        }
        return null;
    }

    @Override
    public String getOrderNotemp(OrderContent orderContent, Timestamp visitDate, int visitNo) {
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
        String billNumber = df.format(visitDate) + visitNo;
        return billNumber;
    }


    @Override
    protected OutpDoctorPrescMaster doOtherInfo(List<ItemData> itemDataList, String testNo, PatientInfo patientInfo, OrderContent order, int age, String testCause,
                                                String clininDiag, Timestamp visitDate, int visitNo, String subject, int outpId) {
        OutpDoctorPrescMaster outpDoctorPrescMaster = new OutpDoctorPrescMaster();
        outpDoctorPrescMaster.setPatientId(patientInfo.getPatientId());
        outpDoctorPrescMaster.setOutpId(outpId);
        outpDoctorPrescMaster.setVisitDate(visitDate);
        outpDoctorPrescMaster.setVisitTime(DateUtil.format(visitDate, "HH:mm"));
        outpDoctorPrescMaster.setVisitNo(Integer.parseInt(testNo.substring(14)));
        outpDoctorPrescMaster.setName(patientInfo.getName());
        outpDoctorPrescMaster.setAge(age);
        outpDoctorPrescMaster.setIdentity(patientInfo.getIdentity());
        outpDoctorPrescMaster.setChargeType(patientInfo.getChargeType());
        outpDoctorPrescMaster.setSex(patientInfo.getSex());
        outpDoctorPrescMaster.setUnitInContract(patientInfo.getUnitInContract());
        outpDoctorPrescMaster.setOrderedBy(order.getOrderedByDept());
        outpDoctorPrescMaster.setPrescriber(order.getOrderedByDoctor());
        outpDoctorPrescMaster.setChargeFlag(0);
        outpDoctorPrescMaster.setPrescType(order.getOrderType().equals("A") ? "0" : "1");
        outpDoctorPrescMaster.setVerifyFlag(0);
        outpDoctorPrescMaster.setDispensary(itemDataList.get(0).getPerformedBy());
        outpDoctorPrescMaster.setOrderType(order.getOrderType());
        outpDoctorPrescMaster.setChronicFlag(order.getChronicFlag());
        return outpDoctorPrescMaster;
    }

    @Override
    protected OutpDoctorPrescItems doOtherInfoDeatil(String orderNo, int itemNo, String itemCode, String itemName, BigDecimal price, BigDecimal charges) {
        return null;
    }

    @Override
    protected BATCH packageMessage(OutpMedrec outpMedrec, List<OutpOrderDescTemp> outpOrderDescTempList, List<Object> objectMaster,
                                   List<Object> objectDetail, OrderInfo orderInfo, PatientInfo patientInfo,
                                   String orc1, String orc5) throws ExceptionHelp {
        return SetFunctionHL7.packageOmallMessage(outpMedrec, outpOrderDescTempList, objectMaster, objectDetail,
                orderInfo.getHospitalCode(), orderInfo.getHospitalName(), orderInfo.getOutpOrInp(), patientInfo,
                orc1, orc5, labTestMasterMapper, AllFinalValueUtils.EAST_DRUG, AllFinalValueUtils.MESSAGE_FROM_PUBLIC,
                AllFinalValueUtils.MESSAGE_EVENT_PRESC, AllFinalValueUtils.MESSAGE_EVENT_NAME_PRESC);
    }


    @Override
    public Object doOtherBillDetail(String testNo, int outpId, Timestamp visitDate, int visitNo, int itemNo,
                                    ClinicItemBill clinicItemBill, ItemData itemData, OrderContent orderContent, String patientId) {
        OutpDoctorPrescItems outpDoctorPrescItems = new OutpDoctorPrescItems();
        outpDoctorPrescItems.setVisitDate(visitDate);
        outpDoctorPrescItems.setVisitNo(visitNo);
        outpDoctorPrescItems.setItemNo(itemNo);
        outpDoctorPrescItems.setItemSubNo(1);
        outpDoctorPrescItems.setItemClass(orderContent.getOrderType());
        outpDoctorPrescItems.setPhamCode(itemData.getItemCode());
        OutpDoctorPrescItems byDurgCode = labTestMasterMapper.getByDurgCode(itemData.getItemCode(), itemData.getItemSpec());
        outpDoctorPrescItems.setPhamName(byDurgCode.getPhamName());
        outpDoctorPrescItems.setPhamSpec(byDurgCode.getPhamSpec());
        outpDoctorPrescItems.setFirmId(byDurgCode.getFirmId());
        outpDoctorPrescItems.setPerAmount(new BigDecimal(itemData.getDosage()));
        outpDoctorPrescItems.setPUnits(byDurgCode.getPUnits());
        outpDoctorPrescItems.setFrequency(itemData.getFrequency());
        outpDoctorPrescItems.setDays(itemData.getDays());
        outpDoctorPrescItems.setAmount(itemData.getAmount());
        outpDoctorPrescItems.setRepetition(0);
        outpDoctorPrescItems.setUnits(byDurgCode.getUnits());
        outpDoctorPrescItems.setNumbers(byDurgCode.getNumbers().multiply(itemData.getAmount()));
        outpDoctorPrescItems.setNUnits(byDurgCode.getNUnits());
        outpDoctorPrescItems.setNumberPerPackage(byDurgCode.getNumberPerPackage());
        outpDoctorPrescItems.setAdministration(itemData.getAdministration());
        outpDoctorPrescItems.setPerformedBy(itemData.getPerformedBy());
        outpDoctorPrescItems.setCosts(itemData.getCosts());
        outpDoctorPrescItems.setCharges(itemData.getCharges());
        outpDoctorPrescItems.setNotes(itemData.getMemo());
        outpDoctorPrescItems.setCosts(itemData.getCosts());
        outpDoctorPrescItems.setCharges(itemData.getCharges());
        return outpDoctorPrescItems;
    }

    @Override
    public Object doAfterData(String type, Object object, BigDecimal costs, BigDecimal charges) {
        Object objecdetail = null;
        switch (type) {
            case OrderConstant.ITEM:
                ItemData itemData = (ItemData) object;
                itemData.setCosts(costs);
                itemData.setCharges(charges);
                objecdetail = doOtherBillDetail(itemData.getOrderNo(), itemData.getOutpId(), itemData.getVisitDate(), itemData.getVisitNo(), itemData.getItemNo(),
                        itemData.getClinicItemBill(), itemData, itemData.getOrderContent(), itemData.getPatientId());
                return objecdetail;
            default:
                OutpDoctorPrescMaster outpDoctorPrescMaster = (OutpDoctorPrescMaster) object;
                return outpDoctorPrescMaster;
        }
    }

    @Override
    public String getReplaceString(BATCH getHl7LabMessage) {
        String utf8 = XMLUtil.convertToXml(getHl7LabMessage).replace(AllFinalValueUtils.MESSAGE_HL7_REPLACE_PRESC_AFT_TARGET, "").
                replace(AllFinalValueUtils.MESSAGE_HL7_REPLACE_PRESC_BEF_TARGET, "").
                replace(AllFinalValueUtils.UNICODE_DEFAULT_TARGET, AllFinalValueUtils.UNICODE_DEFAULT_REPLACEMENT)
                .replace("<type>A</type>", "");
        return utf8;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateOtherTable(ClinicMaster clinicMaster, OutpMedrec outpMedrec, List<OutpOrderDescTemp> outpOrderDescTempList, List<OutpBillItemsTemp> outpBillItemsTempList,
                                    List<OutpDoctorAssistant> outpDoctorAssistantList,
                                    List<Object> objectMasterList, List<Object> objectItemsList, List<Object> objectBillitemsList,
                                    OutpPrepayRcptTemp outpPrepayRcptTemp, List<OrderVsBillno> orderVsBillnoList) throws ExceptionHelp {

        return outpDoctorAssistantService.updateAllTab(AllFinalValueUtils.WEST_DRUG, clinicMaster, outpMedrec, outpOrderDescTempList, outpBillItemsTempList,
                outpDoctorAssistantList, objectMasterList, objectItemsList, objectBillitemsList, outpPrepayRcptTemp, orderVsBillnoList);
    }


    @Override
    public Tip billWork(Receive receive, HttpServletRequest request) throws ExceptionHelp {
        return null;
    }


    @Override
    public Tip orderCancel(CancelOrder CancelOrder, HttpServletRequest request) throws ExceptionHelp {
        return null;
    }

    @Override
    public Tip sendApplyHl7File(OrderInfo orderInfo, String oneKey, String msgType) throws ExceptionHelp {
        Map<String, Object> hl7ApplyBaseData = getHl7ApplyBaseData(oneKey, orderInfo.getPatInfo().getPatientId(), orderInfo.getVisitId());
        List<Object> objectMasterList = new ArrayList<>();
        List<Object> objectDetailList = new ArrayList<>();
        List<OutpOrderDescTemp> outpOrderDescTempList = new ArrayList<>();
        for (ApplyInfo applyInfo : orderInfo.getApplyInfo()) {
            int orderNoumber = applyInfo.getOrder().getOrderNoumber();
            String orderDate = applyInfo.getOrder().getOrderDate();
            String sqlApply = "VISIT_DATE = to_date({0},'yyyy-mm-dd hh24:mi:ss') and visit_no = {1}";
            CompletableFuture outpOrderDesc = CompletableFuture.runAsync(
                    () -> {
                        outpOrderDescTempList.addAll(outpOrderDescTempMapper.selectList(new QueryWrapper<OutpOrderDescTemp>().apply(sqlApply, orderDate, orderNoumber)));
                        List<OutpOrderDesc> outpOrderDescs = outpOrderDescMapper.selectList(new QueryWrapper<OutpOrderDesc>().apply(sqlApply, orderDate, orderNoumber));
                        outpOrderDescs.stream().forEach(outpOrderDesc1 -> {
                            OutpOrderDescTemp outpOrderDescTemp = new OutpOrderDescTemp();
                            BeanUtils.copyProperties(outpOrderDesc1, outpOrderDescTemp);
                            outpOrderDescTempList.add(outpOrderDescTemp);
                        });
                    }, threadPoolExecutor
            );
            CompletableFuture objectMaster = CompletableFuture.runAsync(
                    () -> {
                        objectMasterList.add(outpDoctorPrescMasterMapper.selectList(new QueryWrapper<OutpDoctorPrescMaster>().apply(sqlApply, orderDate, orderNoumber)));
                    }, threadPoolExecutor
            );
            CompletableFuture bjectDetail = CompletableFuture.runAsync(
                    () -> {
                        objectDetailList.addAll(outpDoctorPrescItemsMapper.selectList(new QueryWrapper<OutpDoctorPrescItems>().apply(sqlApply, orderDate, orderNoumber)));

                    }, threadPoolExecutor
            );
            CompletableFuture.allOf(outpOrderDesc, objectMaster, bjectDetail).join();
            BATCH hl7message = packageMessage((OutpMedrec) hl7ApplyBaseData.get("outpMedrec"), outpOrderDescTempList,
                    objectMasterList, objectDetailList,
                    orderInfo, (PatientInfo) hl7ApplyBaseData.get("patientInfo"), "NW", "SC");
            //xml申请文件保存并推送
            oneKey = DateUtil.formatDate(DateUtil.parseTime(applyInfo.getOrder().getOrderDate()), "yyyyMMddHHmmss") + orderNoumber;
            boolean push = saveApplyHl7message(orderInfo.getHospitalCode(), orderInfo.getHospitalName(), oneKey, hl7message, msgType);
            if (!push) {
                throw new ExceptionHelp(ExceptionHelpEnum.SEND_APPLY_MSG_FILAD);
            }
        }
        return new SuccessTip();
    }

}
